home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 February: Tool Chest / Apple Developer CD Series Tool Chest February 1996 (Apple Computer)(1996).iso / Sample Code / Snippets / Processes / Just Finder / Just Finder.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-24  |  11.5 KB  |  333 lines  |  [TEXT/KAHL]

  1. /*
  2.  
  3.     Just Finder
  4.     
  5.     A System 7 application that kills all processes with faces except the Finder.
  6.     Handy for working with Fonts or any other component where you get that blasted
  7.     Finder alert saying "Close everything but the Finder before doing this."
  8.     
  9.     by Matt Deatherage, Developer Support Center
  10.     Copyright 1993 Apple Computer, Inc.  All rights reserved.
  11.     
  12.     MD    Version 1.0 released (9/13/93)
  13.     MD    1.0.1b1.  Don't let Dave code review things if you want to ship.  He reminds us
  14.         that this is not printing, and you shouldn't dispose of AEDesc structures that
  15.         weren't succesfully created.  The comments were right; the code was wrong.
  16.         Also tightened up a loop and removed several extraneous braces left over from
  17.         when this was more complicated.
  18.         
  19.         Also trying pre-compiled headers.  They're by no means necessary, but I've never
  20.         played with them before except for the default MacHeaders.
  21.  
  22. */
  23.  
  24. /*------ Includes ------------------------------------------------------------------------*/
  25.  
  26. #include "JustHeaders"
  27.  
  28. /*------ Prototypes ----------------------------------------------------------------------*/
  29.  
  30. void InstalleAEHandlers(void);
  31. pascal OSErr oappHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon);
  32. pascal OSErr odocHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon);
  33. pascal OSErr pdocHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon);
  34. pascal OSErr quitHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon);
  35. OSErr CheckRequiredParms(AppleEvent *theAppleEvent);
  36. Boolean ShouldWeKill(ProcessInfoRec* processInfo);
  37. void KillThemAll(void);
  38.  
  39. /*------ main ----------------------------------------------------------------------------*/
  40.  
  41. main()
  42.  
  43. {
  44.  
  45. GrafPort myPort;
  46.  
  47.  
  48.     InitGraf((Ptr) &qd.thePort);
  49.     OpenPort((GrafPtr) &myPort);
  50.     InitFonts();
  51.     InitWindows();
  52.     InitMenus();
  53.     TEInit();
  54.     InitDialogs(nil);
  55.     InitCursor();
  56.     
  57.     KillThemAll();
  58.     
  59.  
  60. } /* main */
  61.  
  62. /*******************************************************************************************
  63. *
  64. * According to the rules, all applications that say they're high-level event aware must
  65. * respond to the four required Apple events.  This application has no user interface and
  66. * doesn't deal with documents at all, nor will it quit prematurely.  However, rules is
  67. * rules, so we install four very minimal required event handlers.  The ones with parameters
  68. * return an OSErr that indicates whether all the parameters were read (they weren't, if
  69. * there were any, so it usually returns errAEEventNotHandled).
  70. *
  71. *******************************************************************************************/
  72.  
  73.  
  74.  
  75. /*------ InstallAEHandlers ---------------------------------------------------------------*/
  76.  
  77. void InstallAEHandlers(void)
  78. {
  79.  
  80.     AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,(EventHandlerProcPtr)oappHandler,
  81.                           0,false);
  82.     AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,(EventHandlerProcPtr)odocHandler,
  83.                           0,false);
  84.     AEInstallEventHandler(kCoreEventClass,kAEPrintDocuments,(EventHandlerProcPtr)pdocHandler,
  85.                           0,false);
  86.     AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,(EventHandlerProcPtr)quitHandler,
  87.                           0,false);
  88. }
  89.  
  90. /*******************************************************************************************
  91. *
  92. * CheckRequiredParams is a common Apple event utility routine -- it returns noErr if
  93. * someone has retrieved all the required parameters from the Apple event passed.  If there
  94. * are still some left, it returns errAEEventNotHandled.
  95. *
  96. * The check is simple -- look for the "missed keyword" attribute.  If there isn't one,
  97. * everything is fine.
  98. *
  99. *******************************************************************************************/
  100.  
  101. /*------ CheckRequiredParms ---------------------------------------------------------------*/
  102.  
  103. OSErr CheckRequiredParms(AppleEvent *theAppleEvent)
  104. {
  105.  
  106.     OSErr myErr;
  107.     DescType attrType;
  108.     Size attrSize;
  109.     
  110.     myErr = AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr, typeWildCard,
  111.                               &attrType, 0L, 0, &attrSize);
  112.                               
  113.     if (myErr == errAEDescNotFound)
  114.         myErr = noErr;
  115.         
  116.     if (myErr == noErr)
  117.         myErr = errAEEventNotHandled;
  118.         
  119.     return(myErr);
  120.     
  121. }
  122.  
  123. /*******************************************************************************************
  124. *
  125. * The core AE handlers don't do very much except return errors saying "I didn't do that."
  126. *
  127. *******************************************************************************************/
  128.  
  129. /*------ The core AE handlers -------------------------------------------------------------*/
  130.  
  131. pascal OSErr oappHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
  132. {
  133.  
  134.     return(CheckRequiredParms(theAppleEvent));
  135.  
  136. }
  137.  
  138. pascal OSErr odocHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
  139. {
  140.  
  141.     return(errAEEventNotHandled);
  142.  
  143. }
  144.  
  145. pascal OSErr pdocHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
  146. {
  147.  
  148.     return(errAEEventNotHandled);
  149.  
  150. }
  151.  
  152. pascal OSErr quitHandler(AppleEvent *theAppleEvent, AppleEvent *reply, long refCon)
  153. {
  154.  
  155.     return(CheckRequiredParms(theAppleEvent));
  156.  
  157. }
  158.  
  159. /*******************************************************************************************
  160. *
  161. * ShouldWeKill is the routine that decides if a given process, as specified by a
  162. * ProcessInfoRec, should be killed.  We kill all foreground processes that aren't this
  163. * application or the Finder.  The ProcessInfoRec must be fully initialized by a routine
  164. * very similar to GetProcessInfo or else this routine will probalby do very strange things.
  165. *
  166. *******************************************************************************************/
  167.  
  168. /*------ ShouldWeKill ---------------------------------------------------------------------*/
  169.  
  170. Boolean ShouldWeKill(ProcessInfoRec* processInfo)
  171. {
  172.     
  173.     OSErr myErr;
  174.     ProcessSerialNumber thisProcess;
  175.     Boolean twinProcesses;
  176.     
  177.     thisProcess.highLongOfPSN = 0;
  178.     thisProcess.lowLongOfPSN = kCurrentProcess;        // set up the PSN for this application
  179.     
  180.     myErr = SameProcess(&(processInfo->processNumber), &thisProcess, &twinProcesses);
  181.                                                     // sets up twinProcesses to contain TRUE
  182.                                                     // if the passed process and this one are
  183.                                                     // one and the same
  184.     
  185.     if (!(twinProcesses) &&                            // if this isn't _this_ process and
  186.        !(processInfo->processSignature == 'MACS' && processInfo->processType == 'FNDR') &&
  187.                                                        // if it's not the Finder and
  188.        !(processInfo->processMode & modeOnlyBackground))
  189.                                                        // if it's not background-only then
  190.        {
  191.         return true;                                // Yup, kill it, or do other things to it here.
  192.         } else {
  193.         return false;                                // Nope, it's been spared, or do other things.
  194.        }
  195.  
  196. }
  197.  
  198. /*******************************************************************************************
  199. *
  200. * From looking at published sample code such as ProcDoggie and KillEveryoneButMe (1.0.1),
  201. * you'd think killing a process is a relatively straight-forward thing to do.
  202. *
  203. * Think again.
  204. *
  205. * This took quite some time to figure out, thanks to obscure errors like -603 coming back
  206. * from the Process Manager at strange times.  Here's what I learned, some of which is kind
  207. * of obvious and some of which isn't.
  208. *
  209. * 1.  Don't call GetNextProcess on a process that you've just killed.  It tends to confuse
  210. *     things.  (duh...)  Instead, once we kill a process, we start over at the beginning
  211. *      of the process list, skipping those processes we don't wish to kill.  You know
  212. *      you're done when you hit the end of the process list without killing any processes.
  213. *
  214. * 2.  After killing a process, the Process Manager expects you to keep processing events.
  215. *     Remember the three calls to EventAvail() you have to do at the beginning of most
  216. *      real applications before you become the front process?  In similar ways, the Process
  217. *      Manager might become confused if you're firing off lots of kill events but never
  218. *      call WaitNextEvent to get any.
  219. *
  220. *      So how many times should you call WaitNextEvent?  I've seen numbers from 4 to 25,
  221. *      and they didn't necessarily work for me.  Instead, we call WaitNextEvent until we
  222. *      get a null event, the system's surefire way of indicating it's not doing anything
  223. *      major at this time.  If we get a high-level event, we call AEProcessAppleEvent to
  224. *      follow the rules -- but we ignore other events.
  225. *
  226. *      Note that this might not work for you if you're an application with windows and
  227. *     the like, because you could get an update event.  If you don't process the update
  228. *      event, it won't go away.  This application has no windows and doesn't have to
  229. *      worry about that.
  230. *
  231. *******************************************************************************************/
  232.  
  233.  
  234. /*------ KillThemAll ----------------------------------------------------------------------*/
  235.  
  236. void KillThemAll(void)
  237. {
  238.  
  239.     ProcessSerialNumber theProcess;
  240.     ProcessInfoRec ourProcessInfo;
  241.     OSErr myErr;
  242.     Str31 theProcessName;
  243.     FSSpec theProcessSpec;
  244.     AppleEvent ourQuitEvent, ourReplyEvent;
  245.     AEAddressDesc ourPSNDesc;
  246.     EventRecord theEvent;
  247.     
  248.     // set up the ourProcessInfo record to point to space we've allocated...
  249.     
  250.     ourProcessInfo.processInfoLength = sizeof(ProcessInfoRec);
  251.     ourProcessInfo.processName = (StringPtr)&theProcessName;
  252.     ourProcessInfo.processAppSpec = &theProcessSpec;
  253.     
  254.     theProcess.highLongOfPSN = 0;
  255.     theProcess.lowLongOfPSN = kNoProcess;        // return the first process
  256.  
  257.     while (true) 
  258.         {
  259.         
  260.         // Call WaitNextEvent until we get a null event, meaning all is calm
  261.         
  262.         do {
  263.             WaitNextEvent(everyEvent, &theEvent, 600L, 0L);
  264.             if (theEvent.what == kHighLevelEvent)
  265.                 AEProcessAppleEvent(&theEvent);
  266.             } while (theEvent.what != nullEvent);
  267.             
  268.         myErr = GetNextProcess(&theProcess);
  269.         if (myErr == procNotFound)    
  270.             break;                                // if no process, we're done!
  271.  
  272.         myErr = GetProcessInformation(&theProcess,&ourProcessInfo);
  273.         // Check to see if we want to kill this process
  274.             
  275.         if (ShouldWeKill(&ourProcessInfo))
  276.             {
  277.         
  278.             // Create a process serial number descriptor for this process
  279.             
  280.             myErr = AECreateDesc(typeProcessSerialNumber, (Ptr)&theProcess,
  281.                                  sizeof(theProcess), &ourPSNDesc);
  282.             if (myErr == noErr)
  283.                 {
  284.                 
  285.                 // Create the 'quit' Apple event for this process.  This might return error
  286.                 // -603 for desk accessories if you don't call WaitNextEvent enough times
  287.                 // like above.
  288.                 
  289.                 myErr = AECreateAppleEvent(kCoreEventClass,kAEQuitApplication, &ourPSNDesc,
  290.                                            kAutoGenerateReturnID, kAnyTransactionID, &ourQuitEvent);
  291.                 if (myErr == noErr)
  292.                     {
  293.                     
  294.                     // send the event 
  295.                     
  296.                     myErr = AESend(&ourQuitEvent, &ourReplyEvent, kAENoReply,
  297.                                    kAENormalPriority, kNoTimeOut, 0L, 0L);
  298.                                    
  299.                     if (myErr == noErr)
  300.                         {
  301.                         
  302.                         // Sadly, some applications won't respond to Apple events and do
  303.                         // what they're supposed to do until they're brought to the front,
  304.                         // so we do that, and continue our work in the background.
  305.  
  306.                         SetFrontProcess(&theProcess);
  307.                         
  308.                         }
  309.  
  310.                         // dispose of the event only if we succesfully created it.
  311.                         
  312.                         myErr = AEDisposeDesc(&ourQuitEvent);
  313.                     }
  314.                 
  315.                 // dispose of the descriptor only if we succesfully created it.
  316.                 
  317.                 myErr = AEDisposeDesc(&ourPSNDesc);
  318.             
  319.                 }
  320.             
  321.             // Now, since we killed a process, we don't want to call GetNextProcess
  322.             // on the one we just eliminated!  (That would be bad.)  So we reset our
  323.             // process record to contain the serial number of "no process", so the
  324.             // next call to GetProcessInfo returns the first process, and we start
  325.             // all over again.
  326.             
  327.             theProcess.highLongOfPSN = 0;
  328.             theProcess.lowLongOfPSN = kNoProcess;        // return to the first process
  329.             }
  330.         }
  331. }
  332.     
  333.